#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <vector>
#include <string.h>
#include <sstream>
#include <algorithm>
#include <poll.h>
#include "rtsp_client.h"
#include "../util/rtsp_common.h"
#define RTSP_DEBUG

void ExtractRealmAndNonce(const std::string &authenticate, std::string &realm, std::string &nonce){
    size_t pos = authenticate.find("realm=\"");
    if(pos != std::string::npos){
        pos += 7; // length of 'realm="'
        size_t end = authenticate.find("\"", pos);
        if(end != std::string::npos){
            realm = authenticate.substr(pos, end - pos);
        }
    }
    pos = authenticate.find("nonce=\"");
    if(pos != std::string::npos){
        pos += 7; // length of 'nonce="'
        size_t end = authenticate.find("\"", pos);
        if(end != std::string::npos){
            nonce = authenticate.substr(pos, end - pos);
        }
    }
}

RtspClient::RtspClient(enum TRANSPORT transport){
    rtp_transport_ = transport;
}

RtspClient::~RtspClient(){}


////////////////////////////////////////////////////////
/// RTSP请求响应
///////////////////////////////////////////////////////
// （请求格式）
// OPTIONS rtsp://example.com/media RTSP/1.0
// CSeq: 1
// User-Agent: MyRTSPClient/1.0
int RtspClient::SendOPTIONS(const char *url){
    char result[512] = {0};
    sprintf(result, "OPTIONS %s RTSP/1.0\r\n"
                    "CSeq: %d\r\n"
                    "User-Agent: %s\r\n"
                    "\r\n",
            url,
            cseq,
            USER_AGENT);
    int ret = send(rtsp_sd_, result, strlen(result), 0);
#ifdef RTSP_DEBUG
    std::cout <<  __FILE__ << __LINE__ << std::endl;
    std::cout <<  result << std::endl;
#endif
    cseq++;
    return ret;
}
// （响应格式）
// RTSP/1.0 200 OK
// CSeq: 1
// Public: DESCRIBE, SETUP, PLAY, TEARDOWN
int RtspClient::DecodeOPTIONS(const char *buffer, int len){
    std::string str = buffer;
    struct ResponseMessage parsed_message;
    int used_bytes = ParseRTSPMessage(str, parsed_message);
    buffer_cmd_used_ += used_bytes;
    if(parsed_message.code < 0){ // internal error
        return -1;
    }
    rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_DESCRIBE;
    // printf("code:%d\n",parsed_message.code);
    // printf("stat:%s\n",parsed_message.message.c_str());
    // for (const auto& kvp : parsed_message.result) {
    //     std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
    // }
    return 0;
}
// （请求格式）
// DESCRIBE rtsp://example.com/media RTSP/1.0
// CSeq: 2
// Accept: application/sdp
int RtspClient::SendDESCRIBE(const char *url, const char *authorization){
    char result[512] = {0};
    sprintf(result, "DESCRIBE %s RTSP/1.0\r\n"
                    "CSeq: %d\r\n"
                    "User-Agent: %s\r\n"
                    "Accept: application/sdp\r\n",
            url,
            cseq,
            USER_AGENT);
    if(authorization){
        sprintf(result+strlen(result),"Authorization: %s\r\n",authorization);
    }
    sprintf(result+strlen(result),"\r\n");
    cseq++;
    int ret = send(rtsp_sd_, result, strlen(result), 0);
#ifdef RTSP_DEBUG
    std::cout <<  __FILE__ << __LINE__ << std::endl;
    std::cout <<  result << std::endl;
#endif
    return ret;
}

// （响应格式）
// RTSP/1.0 200 OK
// CSeq: 2
// Content-Type: application/sdp
// Content-Length: 158

// v=0
// o=- 12345 12345 IN IP4 192.168.1.1
// s=Media Session
// t=0 0
// a=recvonly
// m=video 49170 RTP/AVP 96
// a=rtpmap:96 MP4V-ES/90000
// a=control:rtsp://example.com/media/video
int RtspClient::DecodeDESCRIBE(const char *url, const char *buffer, int len){
    std::string str = buffer;
    struct ResponseMessage parsed_message;
    int used_bytes = ParseRTSPMessage(str, parsed_message);
    buffer_cmd_used_ += used_bytes;
    if(parsed_message.code < 0){ // internal error
        return -1;
    }
    if(parsed_message.code == 401){ // Unauthorized
        std::string authenticate = GetValueByKey(parsed_message.result, "WWW-Authenticate");
        if(authenticate.empty()){
            buffer_cmd_used_ -= used_bytes;
            return 0;
        }
        ExtractRealmAndNonce(authenticate, realm_, nonce_);
        std::string response = GenerateAuthResponse(url_info_.username.c_str(), url_info_.password.c_str(), realm_.c_str(), nonce_.c_str(), url, "DESCRIBE");
        std::string res = GenerateAuthHeader(url, response);
        SendDESCRIBE(url, res.c_str());
        return 0;
    }
    else{ // 解析SDP
        // printf("code:%d\n",parsed_message.code);
        // printf("stat:%s\n",parsed_message.message.c_str());
        // printf("sdp:%s\n",parsed_message.sdp.c_str());
        // for (const auto& kvp : parsed_message.result) {
        //     std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
        // }
        std::string content_len_str = GetValueByKey(parsed_message.result, "Content-Length");
        if(content_len_str.empty() || !parsed_message.find_payload){
            buffer_cmd_used_ -= used_bytes;
            return 0;
        }
        int content_len = std::stoi(content_len_str);
        if((len - used_bytes) < content_len){ 
            buffer_cmd_used_ -= used_bytes;
            return 0;
        }
        parsed_message.sdp = str.substr(used_bytes, content_len);
        buffer_cmd_used_ += content_len;
        content_base_ = GetValueByKey(parsed_message.result, "Content-Base");
        if(content_base_.empty()){
            content_base_ = url;
        }
        if(sdp_ == NULL){
            sdp_ = new SDPParse(parsed_message.sdp, content_base_);
            sdp_->Parse();
            video_url_ = sdp_->GetVideoUrl();
            audio_url_ = sdp_->GetAudioUrl();
        }
    }
    rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_STEUP;
    return 0;
}

// (构建请求)
// SETUP rtsp://example.com/media/trackID=1 RTSP/1.0
// CSeq: 3
// Transport: RTP/AVP;unicast;client_port=8000-8001
int RtspClient::SendSTEUP(const char *url){
    std::string authenticate;
    // 1. 生成身份验证头部信息
    if(!realm_.empty() && !nonce_.empty()){
        std::string response = GenerateAuthResponse(url_info_.username.c_str(), url_info_.password.c_str(), realm_.c_str(), nonce_.c_str(), url, "SETUP");
        authenticate = GenerateAuthHeader(url, response);
    }

    // 2. 构建请求消息头
    char result[512] = {0};
    sprintf(result, "SETUP %s RTSP/1.0\r\n"
                    "CSeq: %d\r\n"
                    "User-Agent: %s\r\n",
            url,
            cseq,
            USER_AGENT);

    // 3. 添加身份验证头部信息和会话头部信息
    if(!authenticate.empty()){
        sprintf(result+strlen(result),"Authorization: %s\r\n",authenticate.c_str());
    }
    if(!session_.empty()){
        sprintf(result+strlen(result),"Session: %s\r\n",session_.c_str());
    }

    // 4. 添加传输协议信息，根据RTP传输协议不同，生成不同的Transport头部信息
    if(rtp_transport_ == TRANSPORT::RTP_OVER_UDP){
        if(std::string(url) == video_url_){
            if(CreateRtpSockets(&rtp_sd_video_, &rtcp_sd_video_, &rtp_port_video_, &rtcp_port_video_) < 0){
                std::cout << "video CreateRtpSockets error" << std::endl;
                return -1;
            }
            sprintf(result+strlen(result),"Transport: RTP/AVP;unicast;client_port=%d-%d\r\n",rtp_port_video_, rtcp_port_video_);
        }
        else if(std::string(url) == audio_url_){
            if(CreateRtpSockets(&rtp_sd_audio_, &rtcp_sd_audio_, &rtp_port_audio_, &rtcp_port_audio_) < 0){
                std::cout << "audio CreateRtpSockets error" << std::endl;
                return -1;
            }
            sprintf(result+strlen(result),"Transport: RTP/AVP;unicast;client_port=%d-%d\r\n",rtp_port_audio_, rtcp_port_audio_);
        }
        else{
            return -1;
        }
    }
    else{
        if(std::string(url) == video_url_)
            sprintf(result+strlen(result),"Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n", sig0_video_, sig0_video_ + 1);
        else if(std::string(url) == audio_url_)
            sprintf(result+strlen(result),"Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n", sig0_audio_, sig0_audio_ + 1);
        else
            return -1;
    }

    // 5. 结束请求
    sprintf(result+strlen(result),"\r\n");
    cseq++;

    // 6. 发送请求
    int ret = send(rtsp_sd_, result, strlen(result), 0);
#ifdef RTSP_DEBUG
    std::cout <<  __FILE__ << __LINE__ << std::endl;
    std::cout <<  result << std::endl;
#endif
    return ret;
}

// （解析响应）
// RTSP/1.0 200 OK
// CSeq: 3
// Transport: RTP/AVP;unicast;server_port=9000-9001;ssrc=12345678
int RtspClient::DecodeSTEUP(const char *url, const char *buffer, int len){
    // 1. 解析RTSP响应消息
    std::string str = buffer;
    struct ResponseMessage parsed_message;
    int used_bytes = ParseRTSPMessage(str, parsed_message);
    buffer_cmd_used_ += used_bytes;

    // 2. 解析失败处理
    if(parsed_message.code < 0){ // internal error
        return -1;
    }

    // 3.提取并处理会话信息
    std::string session = GetValueByKey(parsed_message.result, "Session");
    if(session.empty()){
        buffer_cmd_used_ -= used_bytes;
        return 0;
    }

    // 4. 会话超时处理
    if(session_.empty()){
        int pos = session.find(';');
        if(pos != std::string::npos)
            session_ = session.substr(0, pos);
        else
            session_ = session;
        pos = session.find("timeout=");
        if(pos != std::string::npos){
            int pos1 = session.find(';', pos);
            std::string timeout_str;
            if(pos1 == std::string::npos){
                timeout_str = session.substr(pos + strlen("timeout="));
            }
            else{
                timeout_str = session.substr(pos + strlen("timeout="), pos1 - pos - strlen("timeout="));
            }
            timeout_ = atoi(timeout_str.c_str());
            std::cout << "timeout_:" << timeout_ << std::endl;
        }
    }

    // 5. 提取并处理传输协议信息
    if(rtp_transport_ == TRANSPORT::RTP_OVER_UDP){
        std::string transport = GetValueByKey(parsed_message.result, "Transport");
        if(transport.empty()){
            buffer_cmd_used_ -= used_bytes;
            return 0;
        }
        int pos = transport.find("server_port=");
        if(pos == std::string::npos){
            std::cout << "server Transport error:" << transport << std::endl;
            return -1;
        }
        int pos1 = transport.find(';',pos);
        std::string port_rtp;
        if(pos1 == std::string::npos)
            port_rtp = transport.substr(pos + strlen("server_port="));
        else
            port_rtp = transport.substr(pos + strlen("server_port="), pos1 - pos - strlen("server_port="));
        if(std::string(url) == video_url_){
            sscanf(port_rtp.c_str(), "%d-%d", &rtp_port_video_server_, &rtcp_port_video_server_);
        }
        else{
            sscanf(port_rtp.c_str(), "%d-%d", &rtp_port_audio_server_, &rtcp_port_audio_server_);
        }
    }
    else{
        // tcp donothing
    }
    // printf("code:%d\n",parsed_message.code);
    // printf("stat:%s\n",parsed_message.message.c_str());
    // for (const auto& kvp : parsed_message.result) {
    //     std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
    // }
    if(!audio_url_.empty() && !audio_setup_){
        audio_setup_ = true;
        if(SendSTEUP(audio_url_.c_str()) <= 0){
            return -1;
        }
        rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_STEUP_ADUIO;
        return 0;
    }
    if(!video_url_.empty() && !video_setup_){
        video_setup_ = true;
        if(SendSTEUP(video_url_.c_str()) <= 0){
            return -1;
        }
        rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_STEUP_VIDEO;
        return 0;
    }
    rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_PLAY;
    return 0;
}

// （构建请求）
// PLAY rtsp://example.com/media RTSP/1.0
// CSeq: 4
// Range: npt=0.000-
int RtspClient::SendPLAY(const char *url){
    char result[512] = {0};
    sprintf(result, "PLAY %s RTSP/1.0\r\n"
                    "CSeq: %d\r\n"
                    "User-Agent: %s\r\n",
            url,
            cseq,
            USER_AGENT);
    std::string authenticate;
    if(!realm_.empty() && !nonce_.empty()){
        std::string response = GenerateAuthResponse(url_info_.username.c_str(), url_info_.password.c_str(), realm_.c_str(), nonce_.c_str(), url, "PLAY");
        authenticate = GenerateAuthHeader(url, response);
    }
    if(!authenticate.empty()){
        sprintf(result+strlen(result),"Authorization: %s\r\n",authenticate.c_str());
    }
    if(!session_.empty()){
        sprintf(result+strlen(result),"Session: %s\r\n",session_.c_str());
    }
    sprintf(result+strlen(result),"Range: npt=0.000-\r\n");
    sprintf(result+strlen(result),"\r\n");
    cseq++;
    int ret = send(rtsp_sd_, result, strlen(result), 0);
#ifdef RTSP_DEBUG
    std::cout <<  __FILE__ << __LINE__ << std::endl;
    std::cout <<  result << std::endl;
#endif
    return ret;
}

// 解析PLAY请求
int RtspClient::DecodePLAY(const char *url, const char *buffer, int len){
    std::string str = buffer;
    struct ResponseMessage parsed_message;
    int used_bytes = ParseRTSPMessage(str, parsed_message);
    buffer_cmd_used_ += used_bytes;
    if(parsed_message.code < 0){ // internal error
        return -1;
    }
    std::string session = GetValueByKey(parsed_message.result, "Session");
    if(session.empty()){
        buffer_cmd_used_ -= used_bytes;
        return 0;
    }
    int pos = session.find("timeout=");
    if(pos != std::string::npos){
        int pos1 = session.find(';', pos);
        std::string timeout_str;
        if(pos1 == std::string::npos){
            timeout_str = session.substr(pos + strlen("timeout="));
        }
        else{
            timeout_str = session.substr(pos + strlen("timeout="), pos1 - pos - strlen("timeout="));
        }
        timeout_ = atoi(timeout_str.c_str());
    }
    rtsp_cmd_stat_ = RTSPCMDSTAT::RTSP_PLAYING;
    return 0;
}